﻿using System;
using Jink.Core.Json.Converters.Shapes.Core;
using XenoGears.Reflection;
using XenoGears.Reflection.Attributes.Snippets;
using System.Linq;
using XenoGears.Assertions;

namespace Jink.Core.Json.Converters.Shapes.Annotations
{
    internal static class JsonShapesRegistry
    {
        public static IJsonPbag ToJsonPbag(this Object obj)
        {
            var snippets = SnippetRegistry.For<JsonPbagProviderAttribute>();
            var passed = snippets.Select(s =>
            {
                try
                {
                    var code = s.Code.BindDelegate<Func<Object, IJsonPbag>>();
                    return Tuple.Create(s, true, code(obj));
                }
                catch (Exception)
                {
                    return Tuple.Create(s, false, (IJsonPbag)null);
                }
            }).Where(entry => entry.Item2).Select(entry => Tuple.Create(entry.Item1.Weight, entry.Item3));

            var first = passed.FirstOrDefault();
            var second = passed.FirstOrDefault();
            (second != null).AssertImplies(first.Item1 > second.Item1);
            return first.Item2;
        }

        public static IJsonSeq ToJsonSeq(this Object obj)
        {
            var snippets = SnippetRegistry.For<JsonSeqProviderAttribute>();
            var passed = snippets.Select(s =>
            {
                try
                {
                    var code = s.Code.BindDelegate<Func<Object, IJsonSeq>>();
                    return Tuple.Create(s, true, code(obj));
                }
                catch (Exception)
                {
                    return Tuple.Create(s, false, (IJsonSeq)null);
                }
            }).Where(entry => entry.Item2).Select(entry => Tuple.Create(entry.Item1.Weight, entry.Item3));

            var first = passed.FirstOrDefault();
            var second = passed.FirstOrDefault();
            (second != null).AssertImplies(first.Item1 > second.Item1);
            return first.Item2;
        }

        public static IJsonMap ToJsonMap(this Object obj)
        {
            var snippets = SnippetRegistry.For<JsonMapProviderAttribute>();
            var passed = snippets.Select(s =>
            {
                try
                {
                    var code = s.Code.BindDelegate<Func<Object, IJsonMap>>();
                    return Tuple.Create(s, true, code(obj));
                }
                catch (Exception)
                {
                    return Tuple.Create(s, false, (IJsonMap)null);
                }
            }).Where(entry => entry.Item2).Select(entry => Tuple.Create(entry.Item1.Weight, entry.Item3));

            var first = passed.FirstOrDefault();
            var second = passed.FirstOrDefault();
            (second != null).AssertImplies(first.Item1 > second.Item1);
            return first.Item2;
        }
    }
}
